package org.apache.ocean.snapshot;

import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.URLDecoder;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.http.HttpException;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.entity.FileEntity;
import org.apache.http.impl.DefaultConnectionReuseStrategy;
import org.apache.http.impl.DefaultHttpResponseFactory;
import org.apache.http.impl.nio.DefaultServerIOEventDispatch;
import org.apache.http.impl.nio.reactor.DefaultListeningIOReactor;
import org.apache.http.nio.protocol.BufferingHttpServiceHandler;
import org.apache.http.nio.reactor.IOEventDispatch;
import org.apache.http.nio.reactor.ListeningIOReactor;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.BasicHttpProcessor;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.HttpRequestHandler;
import org.apache.http.protocol.HttpRequestHandlerRegistry;
import org.apache.http.protocol.ResponseConnControl;
import org.apache.http.protocol.ResponseContent;
import org.apache.http.protocol.ResponseDate;
import org.apache.http.protocol.ResponseServer;

public class NioFileServer {
	public static Logger log = Logger.getLogger(NioFileServer.class.getName());
	BasicHttpProcessor httpProcessor;
	IOEventDispatch ioEventDispatch;
	ListeningIOReactor ioReactor;
	BufferingHttpServiceHandler httpServiceHandler;
	HttpRequestHandlerRegistry httpRequestHandlerRegistry;

	public NioFileServer(InetSocketAddress inetSocketAddress, File directory) throws Exception {
		HttpParams httpParams = new BasicHttpParams(null);
		httpParams.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 5000).setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 8 * 1024).setBooleanParameter(
				CoreConnectionPNames.STALE_CONNECTION_CHECK, false).setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true).setParameter(
				CoreProtocolPNames.ORIGIN_SERVER, "Jakarta-HttpComponents-NIO/1.1");

		httpProcessor = new BasicHttpProcessor();
		httpProcessor.addInterceptor(new ResponseDate());
		httpProcessor.addInterceptor(new ResponseServer());
		httpProcessor.addInterceptor(new ResponseContent());
		httpProcessor.addInterceptor(new ResponseConnControl());

		httpServiceHandler = new BufferingHttpServiceHandler(httpProcessor, new DefaultHttpResponseFactory(),
				new DefaultConnectionReuseStrategy(), httpParams);
		httpRequestHandlerRegistry = new HttpRequestHandlerRegistry();
		httpRequestHandlerRegistry.register("*", new FileRequestHandler(directory));
		httpServiceHandler.setHandlerResolver(httpRequestHandlerRegistry);

		ioEventDispatch = new DefaultServerIOEventDispatch(httpServiceHandler, httpParams);
		ioReactor = new DefaultListeningIOReactor(5, httpParams);
		try {
			ioReactor.listen(inetSocketAddress);
			ioReactor.execute(ioEventDispatch);
		} catch (Throwable throwable) {
			log.log(Level.SEVERE, "", throwable);
		}
	}

	public class FileRequestHandler implements HttpRequestHandler {
		private File directory;

		public FileRequestHandler(File directory) {
			this.directory = directory;
		}

		public void handle(HttpRequest httpRequest, HttpResponse httpResponse, HttpContext httpContext) throws HttpException, IOException {
			String target = httpRequest.getRequestLine().getUri();
			File file = new File(directory, URLDecoder.decode(target, "UTF-8"));
			log.info("file: "+file.getAbsolutePath());
			httpResponse.setStatusCode(HttpStatus.SC_OK);
			FileEntity body = new FileEntity(file, "binary/octet");
			httpResponse.setEntity(body);
		}
	}
}
